<?php

/**
 * SimplifyPHP Framework
 *
 * This file is part of SimplifyPHP Framework.
 *
 * SimplifyPHP Framework is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * SimplifyPHP Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Rodrigo Rutkoski Rodrigues, <rutkoski@gmail.com>
 */

/**
 *
 *
 * @author Rodrigo Rutkoski Rodrigues <rutkoski@gmail.com>
 * @package Simplify_Kernel_Core
 */
class ConnectionRouterImpl implements IRouter
{

  /**
   *
   * @var array
   */
  protected $connects = array();

  /**
   *
   * @var array
   */
  protected $absolute = array();

  public function build($id, $params = array())
  {
    if (strpos($id, '/') !== false || empty($id)) {
      return $id;
    }

    if (! isset($this->connects[$id])) {
      throw new RouterException("Unknow route id: <b>$id</b>");
    }

    $route = $this->connects[$id];

    $_route = $route['route'];

    if (! empty($route['names'])) {
      $names = array_flip($route['names']);

      foreach ($route['defaults'] as $k => $v) {
        if (! isset($params[$k]) && ! isset($route['defaults'][$k])) {
          $params[$k] = $v;
        }
      }

      foreach ($route['names'] as $name) {
        if (! isset($params[$name]) && ! isset($route['defaults'][$name])) {
          throw new RouterException("Missing route parameter: <b>$name</b>");
        }

        if (isset($params[$name])) {
          $_route = str_replace('/:' . $name, '/' . $params[$name], $_route);
        }
        else {
          $_route = str_replace('/:' . $name, '', $_route);
        }
      }
    }

    return $_route;
  }

  public function connect($id, $route, $defaults = array(), $match = array())
  {
    $words = array_filter(split('/', $route));

    $regex = array();
    $names = array();
    $index = 0;

    $absolute = true;

    foreach ($words as $word) {
      if ($word == '*') {
        $regex[] = '(?:/(.*))?';

        $names[$index++] = 'params';

        $absolute = false;
      }
      else if (strpos($word, ':') === 0) {
        $wildcard = substr($word, 1);

        $names[$index++] = $wildcard;

        if (isset($match[$wildcard])) {
          $regex[] = '/(' . $match[$wildcard] . ')';
        }
        elseif (isset($defaults[$wildcard])) {
          $regex[] = '(?:/([^/]+))?';
        }
        else {
          $regex[] = '/([^/]+)';
        }
        
        $absolute = false;
      }
      else {
        $regex[] = '/' . $word;
      }
    }

    if ($absolute) {
      $this->absolute[$route] = $id;
    }

    $regex = implode('', $regex);
    $regex = '#^' . $regex . '/*$#';

    $connect = array(
      'route' => $route, 'regex' => $regex, 'names' => $names, 'defaults' => $defaults, 'match' => $match
    );

    $this->connects[$id] = $connect;
  }

  public function parse($route)
  {
    if (isset($this->absolute[$route])) {
      preg_match($this->connects[$this->absolute[$route]]['regex'], $route, $r);
      return $this->_parse($r, $this->absolute[$route]);
    }

    $i = 0;
    $keys = array_keys($this->connects);
    $c = count($keys);

    while ($i < $c && ! preg_match($this->connects[$keys[$i]]['regex'], $route, $r)) {
      $i ++;
    }

    if ($i < $c) {
      $data = $this->_parse($r, $keys[$i]);
    }

    if (empty($data)) {
      throw new RouteNotFoundException("Could not parse route: <b>$route</b>");
    }

    return $data;
  }

  protected function _parse($r, $i)
  {
    array_shift($r);

    $connect = $this->connects[$i];

    $data = $connect['defaults'];
    foreach ($connect['names'] as $key => $name) {
      $value = sy_get_param($r, $key, sy_get_param((array) $connect['defaults'], $name));

      if ($name == 'params') {
        $value = ( array ) explode('/', $value);
      }

      $data[$name] = $value;
    }

    foreach ((array)$connect['defaults'] as $name => $value) {
      if (preg_match_all('/\:([^\/]+)/', $value, $r)) {
        foreach ($r[1] as $wildcard) {
          $data[$name] = str_replace(':' . $wildcard, $data[$wildcard], $data[$name]);
        }
      }
    }

    return new Dictionary($data);
  }

}

?>